package com.passer.uam.manager.account;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.passer.toolbox.common.password.encryption.Encrypt;
import com.passer.toolbox.common.file.filter.FilenameFilter;
import com.passer.toolbox.common.file.util.FileUtils;
import com.passer.toolbox.common.core.util.StringUtils;
import com.passer.uam.config.UamConfig;
import com.passer.uam.entity.Account;
import com.twmacinta.util.MD5;
import lombok.extern.slf4j.Slf4j;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
public class AccountManager {

    private final Encrypt encrypt = new Encrypt();

    public void showAccount() {
        List<Account> accountList = new ArrayList<>();
        File folder = new File(UamConfig.getAccountPath());
        if (!folder.exists()) {
            log.error("尚未保存过账号");
            return;
        }
        File[] files = folder.listFiles();
        if (files != null) {
            for (File file : files) {
                accountList.addAll(readAccount(file));
            }
        }
        showAccount(accountList);
    }

    public List<Account> searchAccount(Account account) {
        File folder = new File(UamConfig.getAccountPath());
        if (folder.exists() && StringUtils.isNotEmpty(account.getSource())) {
            String sourceHex = MD5.asHex(account.getSource().getBytes());
            File[] files = folder.listFiles(new FilenameFilter(sourceHex));
            if (files != null && files.length > 0 && FileUtils.checkFileSize(files[0])) {
                return readAccount(files[0]);
            }
        }
        return new ArrayList<>();
    }

    public void showAccount(List<Account> accountList) {
        Map<String, List<Account>> map = accountList.stream().collect(Collectors.groupingBy(Account::getSource));
        for (Map.Entry<String, List<Account>> entry : map.entrySet()) {
            List<Account> value = entry.getValue();
            if (!value.isEmpty()) {
                System.out.println("-------------------------------------");
                System.out.println("账号来源：" + entry.getKey());
                System.out.println("网址：" + value.get(0).getUrl());
                value.forEach(this::showAccount);
            }
        }
    }

    private void showAccount(Account account) {
        String accountInfo = "-------------------------------------\n账号：" + account.getName() + "\n密码：" + account.getPassword() + "\n备注：" + account.getDescription();
        System.out.println(accountInfo);
    }

    public void showAccountInfo(Account account) {
        System.out.println("-------------------------------------");
        String accountInfo = "账号来源：" + account.getSource() + "网址：" + account.getUrl() + "账号：" + account.getName() + "\n密码：" + account.getPassword();
        System.out.println(accountInfo);
    }

    public void saveAccount(Account account) {
        File folder = new File(UamConfig.getAccountPath());
        if (!folder.exists() && !folder.mkdirs()) {
            log.error("无法创建文件夹 {}", folder.getAbsolutePath());
            return;
        }
        if (StringUtils.isEmpty(account.getSource())) {
            log.error("未输入账号来源，保存失败");
            return;
        }
        String sourceHex = MD5.asHex(account.getSource().getBytes());
        File targetFile;
        File[] files = folder.listFiles(new FilenameFilter(sourceHex));
        if (files != null && files.length > 0 && FileUtils.checkFileSize(files[0])) {
            targetFile = files[0];
        } else {
            targetFile = new File(folder, sourceHex);
        }

        String accountEncrypt = encrypt.encrypt(JSONObject.toJSONString(account));
        byte[] bytes = accountEncrypt.getBytes(StandardCharsets.UTF_8);

        try (
                FileOutputStream fileOutputStream = new FileOutputStream(targetFile, true);
                DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream);
        ) {
            for (byte aByte : bytes) {
                dataOutputStream.writeInt(aByte);
            }
            dataOutputStream.flush();

        } catch (IOException e) {
            log.error("账户信息保存失败：{}", e.getMessage());
        }
    }

    private List<Account> readAccount(File file) {
        StringBuilder stringBuilder = new StringBuilder();
        byte[] bytes = new byte[1024];
        int i = 0;
        int readNUmber;
        try (
                FileInputStream fileInputStream = new FileInputStream(file);
                DataInputStream dataInputStream = new DataInputStream(fileInputStream);
        ) {
            while ((readNUmber = dataInputStream.readInt()) != -1) {
                bytes[i++] = (byte) readNUmber;
                if (i == bytes.length) {
                    stringBuilder.append(new String(bytes, StandardCharsets.UTF_8));
                    i = 0;
                }
            }
        } catch (IOException e) {
            if (!(e instanceof EOFException)) {
                log.error("账户信息读取失败", e);
                throw new RuntimeException(e);
            }
        } finally {
            stringBuilder.append(new String(bytes, 0, i, StandardCharsets.UTF_8));
        }
        
        String decrypt = encrypt.decrypt(stringBuilder.toString());
        JSONArray jsonArray = JSONArray.parse("[" + decrypt + "]");
        return jsonArray.toJavaList(Account.class);
    }

}
